#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , addr("0.0.0.0")
    , port(12345)
{
    ui->setupUi(this);

    server = new QTcpServer(this);
    QObject::connect(server,&QTcpServer::newConnection,this,&Widget::onNewConnection);
    server->listen(addr,port);

    classifier = new cv::CascadeClassifier("E:/QT_opencv/etc/haarcascades/haarcascade_frontalface_default.xml");
    if(classifier->empty() == false)
    {
        qDebug() <<"人脸特征库加载成功";
    }

    QFile file("E:/QT_opencv/src/face.xml");
    if(file.exists()){
        recognizer = cv::face::LBPHFaceRecognizer::load<cv::face::LBPHFaceRecognizer>("E:/QT_opencv/src/face.xml");
    }else{
        recognizer = cv::face::LBPHFaceRecognizer::create();
    }
    pen.setColor(Qt::blue);
    pen.setWidth(20);

    //==============================================
    db = new DbHelper("test.db");
    db->createTable("create table if not exists face(label integer primary key autoincrement,name text not null)");

    ui->textEdit->append("---------------------------");
    ui->textEdit->append("姓名  时间   星期  日期  年份");
    ui->textEdit->append("---------------------------");

}

Widget::~Widget()
{
    delete ui;
}

QPixmap Widget::facePredict(QImage &image,myClient* client)
{
    QPixmap pic =QPixmap::fromImage(image);

    cv::Mat org_mat(image.height(),image.width(),CV_8UC4,(void*)image.bits(),image.bytesPerLine());
    cv::Mat gray_mat;
    cv::cvtColor(org_mat,gray_mat,CV_BGR2GRAY);

    classifier->detectMultiScale(gray_mat,faces,1.15,3,0,{90,90},{350,350});

    if(faces.empty() == false)
    {
        painter.begin(&pic);
        painter.setPen(pen);
        cv::Rect rect = faces[0];
        QRect qrect(rect.x,rect.y,rect.width,rect.height);
       // painter.drawRect(rect.x,rect.y,rect.width,rect.height);
        painter.drawRect(qrect);
        painter.end();

        if(flag == 1)
            //人脸录入
                {
                    faceCount++;
                    QImage face_image = image.copy(qrect);
                    cv::Mat face_mat(face_image.height(),face_image.width(),CV_8UC4,(void*)face_image.bits(),face_image.bytesPerLine());
                    cv::Mat gray_face;
                    cv::cvtColor(face_mat,gray_face,CV_BGR2GRAY);

                    int row = db->getRow();
                    qDebug() << "row = " << row;
                    if(row != 0)
                    {
                        int label = 0;
                        double confidence = 0;
                        recognizer->predict(gray_face,label,confidence);
                        qDebug()<<confidence;
                        QString name = db->facePredict(label);
                        if(confidence>=90&&confidence<=100)
                        {
                            qDebug() <<"该人脸已存在";
                            Pack p1;
                            p1.setType(TYPE_FACE);
                            p1.setErr(TYPE_FACE_EXISTS);
                            p1 >> client;
                            flag = 0;
                            return QPixmap();
                        }
                    }



                    int label = db->getRow()+1;//查询数据库中，最大label的值，新增人脸的label的值就是最大label+1

                    setFace.push_back(gray_face);
                    faceFlag.push_back(label);
                    if(faceCount >= 5)
                    {
                        recognizer->update(setFace,faceFlag);
                        setFace.clear();
                        faceFlag.clear();
                        faceCount = 0;
                        flag = 0;

                        QString name = username;
                        db->faceRegist(name,label);
                        qDebug() << "人脸录入成功";
                        Pack p2;
                        p2.setType(TYPE_FACE);
                        p2.setErr(TYPE_FACE_SAVE_OK);
                        p2 >> client;
                    }


                }
                else if(flag == 2)
            //人脸匹配
                {
                    QImage face_image = image.copy(qrect);
                    cv::Mat face_mat(face_image.height(),face_image.width(),CV_8UC4,(void*)face_image.bits(),face_image.bytesPerLine());
                    cv::Mat gray_face;
                    cv::cvtColor(face_mat,gray_face,CV_BGR2GRAY);

                    int label = 0;
                    double confidence = 0;//用来接收返回的人脸置信度
                    recognizer->predict(gray_face,label,confidence);
                    QString name = db->facePredict(label);

                    if(name != NULL&&confidence>=80&&confidence<=100)
                    {

                        qDebug() <<"欢迎回来"<< name;
                        qDebug()<< "该人脸可信度为:" << confidence;
                        flag = 0;
                        Pack p3;
                        p3.setType(TYPE_FACE);
                        p3.setErr(TYPE_FACE_LOGIN_OK);
                        p3 >> client;

                        QDateTime now = QDateTime::currentDateTime();

                        // 记录精确到秒
                        QString checkTime = now.toString("hh:mm:ss");
                        QString currentDate = QDateTime::currentDateTime().date().toString();
                        name.append(" ");
                        name.append(checkTime);
                        name.append(" ");
                        name.append(currentDate);
                        ui->textEdit->append(name);
                    }
                }
    }

    return pic;
}

void Widget::sendFace(QPixmap &pic,myClient* client)
{
    QImage image = pic.toImage();
    Pack pack;
    pack.setType(TYPE_CAMERA_TRANSLATING);

    QByteArray arr;
    QBuffer buf(&arr);
    image.save(&buf,"JPG");

    int image_size = arr.size();
    int writed_size = 0;
    while(1){
        if(writed_size + 4096 >= image_size){
            pack.setType(TYPE_CAMERA_TRANSLATE_END);
            pack.append(arr.data()+writed_size,image_size-writed_size);
            pack >> client;
            break;
        }else{
            pack.append(arr.data()+writed_size,4096);
            pack >> client;
        }
        writed_size += 4096;
    }
}




void Widget::onNewConnection()
{
    QTcpSocket* c = server->nextPendingConnection();

    myClient* client = new myClient(c);
    QObject::connect(client,&myClient::disconnected,this,&Widget::onDisConnected);
    QObject::connect(client,&myClient::readyRead,this,&Widget::onReadyRead);

}

void Widget::onDisConnected()
{

}



void Widget::onReadyRead()
{
    // 只要进到这个槽函数，就说明有客户端发消息了
    QObject* obj = QObject::sender();
    myClient* client = dynamic_cast<myClient*>(obj);
    int res = -1;
    while(1){
        int size = 0;
        Pack pack;

        if(client->unreaded_pack_size != 0){
            res = client->read((char*)&client->readed_pack+client->readed_pack_size,client->unreaded_pack_size);
            if(client->unreaded_pack_size != res){
                client->unreaded_pack_size -= res;
                client->readed_pack_size += res;
                break;
            }
            client->unreaded_pack_size = 0;
            pack = client->readed_pack;
            size = *(int*)&pack;
        }else{
            if(client->unreaded_size_size != 0){
                client->read((char*)&client->readed_size+client->readed_size_size,client->unreaded_size_size);
                client->unreaded_size_size = 0;
                size = client->readed_size;
            }else{
                res = client->read((char*)&size,4);
                if(size == 0){break;}
                if(res != 4){
                    client->readed_size_size = res;
                    client->unreaded_size_size = 4 - res;
                    memcpy(&client->readed_size,&size,client->readed_size_size);
                    break;
                }
            }
           // qDebug() << "size = " << size;

            res = client->read((char*)&pack+4,size-4);
            *((int*)&pack) = size;
            if(res != size - 4){
               // qDebug() << "发生分包";
                client->readed_pack_size = res + 4;
                client->unreaded_pack_size = size - client->readed_pack_size;
                memcpy(&client->readed_pack,&pack,client->readed_pack_size);
                break;
            }

        }

    // ====================================================================================================================
    //  以下为协议包处理部分
    // ====================================================================================================================


        switch (pack.getType()) {
            case TYPE_CAMERA_TRANSLATING:{
                camera_image += pack.getByteArray(*(int*)&pack - 12);
                break;
            }
            case TYPE_CAMERA_TRANSLATE_END:{
                camera_image += pack.getByteArray(*(int*)&pack  - 12);
                QBuffer buf(&camera_image);// 以camera_image 为内存，创建buf，所以现在buf里面保存了一帧图片
                QImageReader reader(&buf,"jpg");// 以buf为数据源，将图片以jpg的形式，构建一个reader
                // 所以现在reader里面有一帧jpg格式的图片
                QImage image = reader.read();// 将reader里面的一帧图片读取出来，赋值给image
                image = image.scaled(ui->label->size());
                //QPixmap pic = QPixmap::fromImage(image);
                QPixmap pic = facePredict(image,client);

                ui->label->setPixmap(pic);
                if(pic.isNull() == false){
                    sendFace(pic,client);
                }
                camera_image.clear();
                break;
            }
            case TYPE_FACE:{
               QStringList list = pack.analysis();
               flag = list[0].toInt();
               int mode = list[1].toInt();
               if(mode == 1)
               {
                   username = list[2];
               }
                break;
            }

        }



    }
}

